package com.koron.standard.excel;


import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 同值列合并策略
 * @author jzp
 * @since 2022/5/16
 */
public class SameValueColumnMergeStrategy<T> extends AbstractMergeStrategy {
    /**
     * {
     *     columnIndex: {
     *         startRowIndex: endRowIndex
     *     }
     * }
     */
    private final Map<Integer, Map<Integer, Integer>> mergeMap = new HashMap<>();

    /**
     * @param list 表格数据
     * @param needMergeColumn 需要合并的列索引，从0开始
     */
    public SameValueColumnMergeStrategy(List<T> list, Set<Integer> needMergeColumn) throws IllegalAccessException {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        Map<Integer, List<Object>> integerListMap = rowToColMap(list, needMergeColumn);
        integerListMap.forEach((columnIndex, columnList) -> {
            Map<Integer, Integer> cellMap = mergeMap.getOrDefault(columnIndex, new HashMap<>());
            int preIndex = 0;
            for (int i = 1; i < columnList.size(); i++) {
                if (Objects.equals(columnList.get(i), columnList.get(preIndex))) {
                    cellMap.put(preIndex, i);
                } else {
                    preIndex = i;
                }
            }
            mergeMap.put(columnIndex, cellMap);
        });
    }

    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
        Map<Integer, Integer> rowMergeMap;
        if ((rowMergeMap = mergeMap.get(cell.getColumnIndex())) != null && rowMergeMap.get(relativeRowIndex) != null){
            int headHeight = cell.getRowIndex() - relativeRowIndex; // 表头高度
            CellRangeAddress cellRangeAddress = new CellRangeAddress(cell.getRowIndex(), rowMergeMap.get(relativeRowIndex) + headHeight, cell.getColumnIndex(), cell.getColumnIndex());
            sheet.addMergedRegionUnsafe(cellRangeAddress);
        }
    }

    /**
     * 行转列
     *
     * @param list            需要转化的表格
     * @param needMergeColumn 表格中需要转化的列索引集合
     * @return 转化后的map，key为列索引，value为列值
     * @throws IllegalAccessException 权限不足时抛出
     */
    public Map<Integer, List<Object>> rowToColMap(List<T> list, Set<Integer> needMergeColumn) throws IllegalAccessException {
        // null时为所有列
        if (!CollectionUtils.isEmpty(list) && CollectionUtils.isEmpty(needMergeColumn)) {
            T t = list.get(0);
            Field[] declaredFields = t.getClass().getDeclaredFields();
            needMergeColumn = IntStream.range(0, declaredFields.length).boxed().collect(Collectors.toSet());
        }

        Map<Integer, List<Object>> map = new HashMap<>();
        for (Integer integer : needMergeColumn) {
            map.put(integer, new ArrayList<>());
        }
        for (T t : list) {
            Field[] declaredFields = t.getClass().getDeclaredFields();
            for (Integer columnIndex : needMergeColumn) {
                Field field = declaredFields[columnIndex];
                field.setAccessible(true);
                Object o = field.get(t);
                List<Object> columnList = map.get(columnIndex);
                columnList.add(o);
            }
        }
        return map;
    }
}
